﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SerialChart
{
    /// <summary>
    /// 数据工厂抽象类
    /// 提供发送定时器和接收线程
    /// 提供数据接收与发送事件
    /// 提供接收与发送计数
    /// 提供通信状态标识
    /// 接收实现IDataStream接口的数据流
    /// 版本 V1.0.3
    /// 修改历史：
    /// 添加帧解析器支持
    /// 统一委托
    /// </summary>
    public abstract class FrameFactory
    {
        public delegate void FrameHandler(EventArgs e);

        //发送正确协议帧事件
        public event FrameHandler FrameSended;
        //收到正确协议帧事件
        public event FrameHandler FrameReceived;
        //通信状态改变事件
        public event FrameHandler ConnStateChanged;

        #region 变量
        /// <summary>
        /// 接收计数
        /// </summary>
        public int RecCnt = 0;
        /// <summary>
        /// 发送计数
        /// </summary>
        public int SendCnt = 0;
        /// <summary>
        /// 发送定时器发送间隔
        /// </summary>
        public int SendInterval
        {
            get { return timer.Interval; }
            set { timer.Interval = value; }
        }
        /// <summary>
        /// 通信状态标记
        /// </summary>
        public bool isConnected = false;
        private int connCnt;//判断是否有数据通信次数，连续未收到回复视为通信中断
        //处理流
        protected IFrameStream stream;
        /// <summary>
        /// 帧解析器
        /// 实现IFrameParser接口
        /// </summary>
        protected IFrameParser Parser;
        //接收线程
        private Thread parserThead;
        //发送定时器
        protected System.Windows.Forms.Timer timer;
        //接收进程运行标志
        protected bool keepRec = false;

        //发送、接收进程启动使能
        //如需手动控制协议帧的接收和发送，请禁用自动收发
        public bool EnableAutoSend = false;
        public bool EnableAutoRec = true;
        #endregion

        #region 事件
        protected virtual void OnFrameSended(EventArgs e)
        {
            if (connCnt < 0)//每正确发送一次协议帧，通讯延时计数减一，小于零则认为通信中断
            {
                if (isConnected != false)
                {
                    isConnected = false;
                    if (ConnStateChanged != null)
                        this.ConnStateChanged(EventArgs.Empty);
                }

            }
            else
            {
                connCnt--;
            }
            SendCnt++;
            if (this.FrameSended != null)
            {
                this.FrameSended(e);
            }
        }
        protected virtual void OnFrameReceived(EventArgs e)
        {
            connCnt = 10;//每次收到数据，代表通讯正常，重置连接延时计数
            if (isConnected != true)
            {
                isConnected = true;
                if (ConnStateChanged != null)
                    this.ConnStateChanged(EventArgs.Empty);
            }
            RecCnt++;
            if (this.FrameReceived != null)
            {
                this.FrameReceived(e);
            }
        }
        #endregion

        #region 方法
        public FrameFactory(IFrameStream _stream)
        {
            //初始化数据流
            if (_stream != null)
            {
                stream = _stream;
            }
            else
            {
                throw new Exception("流不能为空");
            }
            //初始化发送定时器
            timer = new System.Windows.Forms.Timer();
            timer.Tick += timer_Tick;
        }

        /// <summary>
        /// 开启数据发送和解析线程
        /// </summary>
        public virtual void StartProc()
        {
            //开始流
            stream.Start();
            if (EnableAutoSend)
            {
                //开启发送定时器进程
                timer.Enabled = true;
            }
            if (EnableAutoRec)
            {
                //开启解析进程？？？（将线程创建放入构造函数，在StartProc，StopProc中只设置keepRec控制线程运行）
                keepRec = true;
                parserThead = new Thread(FrameRecThread);
                parserThead.IsBackground = true;
                parserThead.Start();
            }
        }
        /// <summary>
        /// 停止数据发送和解析线程
        /// </summary>
        public virtual void StopProc()
        {
            stream.Stop();
            //关闭发送定时器进程
            timer.Enabled = false;
            //关闭解析进程
            keepRec = false;
            parserThead.Abort();
        }

        void timer_Tick(object sender, EventArgs e)
        {
            FrameSendThread();
        }

        /// <summary>
        /// 协议帧发送线程，定时器驱动
        /// </summary>
        protected virtual void FrameSendThread()
        {

        }
        /// <summary>
        /// 协议帧接收线程
        /// </summary>
        protected virtual void FrameRecThread()
        {
            while (keepRec)
            {
                if (stream.available > 0)
                {
                    stream.Read();
                }
            }
        }
        /// <summary>
        /// 挂载帧协议解析
        /// </summary>
        /// <param name="parser">解析器</param>
        public void LoadParser(IFrameParser parser)
        {
            Parser = parser;
        }
        #endregion

    }

    public interface IFrameStream
    {
        int available { get; }
        void Start();
        void Stop();
        Byte Read();
        void Send(Byte[] data);
    }

    public interface IFrameParser
    {
        void Parse(Frame frame);
    }
}
